package cn.wizzer.framework.util;

import cn.wizzer.framework.base.exceptions.BizException;
import cn.wizzer.framework.base.model.enums.BizExceptionEnum;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

public class Result implements Serializable {

    private static final Log log = Logs.get();

    private static final long serialVersionUID = 1L;

    private int code;
    protected Object msg;
    private Object data;
    private String detail;
    private String key;


    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Result() {

    }


    public static Result NEW() {
        return new Result();
    }

    public static void response(HttpServletResponse response, HTTP_STATUS code, Map<String, String> header, byte[] body) {
        response(response, code, header, new String(body));
    }

    public static void response(HttpServletResponse response, HTTP_STATUS code, Map<String, String> header, Object body) {
        response.reset();
        response.setStatus(code.CODE);
        if (null != header && header.keySet().size() > 0) {
            header.forEach(response::setHeader);
        }
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.print(body.getClass().equals(String.class) ? (String) body : JSONObject.toJSONString(body));
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            if (null != outputStream) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }


    }

    public static void error(HttpServletResponse response, String msg) {
        ServletOutputStream print = null;
        try {
            response.setContentType("text/html; charset=utf-8");
            response.setCharacterEncoding(Charsets.UTF_8.name());
            print = response.getOutputStream();
            print.print(JSONUtil.toJSONString(error(msg)));
        } catch (IOException ignore) {
        } finally {
            if (print != null) {
                try {
                    print.flush();
                    print.close();
                } catch (IOException ignore) {
                }
            }
        }
    }

    public static void error(HttpServletResponse response, int code) {
        ServletOutputStream print = null;
        try {
            response.setContentType("text/html; charset=utf-8");
            response.setCharacterEncoding(Charsets.UTF_8.name());
            print = response.getOutputStream();
            print.print(JSONUtil.toJSONString(new Result(code, null, null)));
        } catch (IOException ignore) {
        } finally {
            if (print != null) {
                try {
                    print.flush();
                    print.close();
                } catch (IOException ignore) {
                }
            }
        }
    }

    public static void error(HttpServletResponse response, BizExceptionEnum msg, String detail) {
        if (!(response.getStatus() == 500)) {
            ServletOutputStream print = null;
            try {
                response.setContentType("text/html; charset=utf-8");
                response.setCharacterEncoding(Charsets.UTF_8.name());
                print = response.getOutputStream();
                Result error = error(msg);
                error.setDetail(detail);
                print.print(JSONUtil.toJSONString(error));
            } catch (IOException ignore) {
            } finally {
                if (print != null) {
                    try {
                        print.flush();
                        print.close();
                    } catch (IOException ignore) {
                    }
                }
            }
        }
    }

    public static void error(HttpServletResponse response) {
        try {
            ServletOutputStream print = response.getOutputStream();
            print.print(JSONUtil.toJSONString(error()));
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    public static void breakWith(BizExceptionEnum cause) {
        throw BizException.NEW(cause);
    }

    public static void breakWith(String cause) {
        throw new BizException(cause);
    }

    public Result addCode(int code) {
        this.code = code;
        return this;
    }

    public Result addDetail(String detail) {
        this.detail = detail;
        return this;
    }

    public Result addData(Object data) {
        this.data = data;
        return this;
    }

    public Result(int code, BizExceptionEnum msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public Result(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public static Result success(BizExceptionEnum msg) {
        return new Result(0, msg, null);
    }

    public static Result success(BizExceptionEnum msg, Object data) {
        return new Result(0, msg, data);
    }

    public static Result success(Object data) {
        return new Result(0, null, data);
    }

    public static Result success(String msg) {
        return new Result(0, msg);
    }

    public static Result successNonNull(Object data) {
        if (data == null) {
            return Result.error();
        }
        return new Result(0, null, Objects.requireNonNull(data));
    }

    public static Result error(int code, BizExceptionEnum msg) {
        return new Result(code, msg, null);
    }

    public static Result error(BizExceptionEnum msg, Object data) {
        return new Result(-1, msg, data);
    }

    public static Result error(BizExceptionEnum msg) {
        return new Result(-1, msg, null);
    }

    public static Result error(String msg) {
        return new Result(-1, msg);
    }

    public static Result success() {
        return new Result(0, null, null);
    }

    public static Result error() {
        return new Result(-1, null, null);
    }


    public int getCode() {
        return code;
    }

    public Object getData() {
        return data;
    }

    public String getMsg() {
        return msg == null ? null : msg.toString();
    }

    public Result setMsg(BizExceptionEnum msg) {
        this.msg = msg;
        return this;
    }

    public Result setMsg(String msg) {
        this.msg = msg;
        return this;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public String getDetail() {
        return detail;
    }

    public Result addKey(String key) {
        this.key = key;
        return this;
    }

    public enum HTTP_STATUS {
        OK(200), ERROR(500);

        public final Integer CODE;

        HTTP_STATUS(Integer code) {
            this.CODE = code;
        }

    }

    public static <K, V> Map<K, V> createMap(Object... args) {
        TreeMap<K, V> map = new TreeMap<>();
        for (int i = 0; i < args.length; i += 2) {
            map.put((K) args[i], (V) args[i + 1]);
        }
        return map;
    }

    public static <K, V> Map<K, V> createHashMap(Object... args) {
        HashMap<K, V> map = new HashMap<>();
        for (int i = 0; i < args.length; i += 2) {
            map.put((K) args[i], (V) args[i + 1]);
        }
        return map;
    }

    public static <T> ArrayList<T> createList(T... args) {
        ArrayList<T> arrayList = new ArrayList<>();
        arrayList.addAll(Arrays.stream(args).collect(Collectors.toList()));
        return arrayList;
    }

}

